Modern operating systems drive many of today's technology-based innovations by offering a platform for both hardware and software development while serving many diverse needs. These systems have evolved from more simplistic file management systems to more complex workstations that provide high-end performance at reasonable cost. Such systems often include multi-processing architectures, high-speed memory, advanced peripheral devices, a variety of system libraries and components to aid software development, and intricate/interleaved bus architectures, for example. At the heart of these systems include sophisticated operating systems that manage not only computer-related hardware but, a vast array of software components having various relationships. These components are often described in terms of objects or classes having multi-tiered relationships such as in a hierarchical arrangement for files and directories that are found in many data management systems.
Event driven programs that operate in a multi-threaded environment are generally concerned with synchronization between various components associated with the event. Such programs execute code in response to events (callbacks from a system to program supplied functions), and typically implement a state machine that responds to the event and returns. In an object structured, multi-threaded system, events may occur concurrently from the same or different objects. Due to this concurrency, the data in the program can become corrupt due to concurrent modification by two or more concurrent events.
This concurrency in the program is usually mitigated by a series of locks (code that temporally prevents other code from completion) associated with the data which serialize the sections of code that accesses that data. Manually managing this serialization by separate and unrelated entities (e.g., a device driver having separate discreet code and management from an operating system kernel) can lead to errors in which locks are not utilized when they should be, or not released when the code returns. Also errors occur by separate, unrelated modules in which locks should be acquired and released in a consistent order, and if not—the program causes a deadlock.
The level of effort, and complexity of such program code increases with each event and data instance that is to be synchronized, thus causing writing a reliable version of the code a time consuming and difficult task. The chance of shipping a latent synchronization bug with the program increases along with this complexity since not all synchronization cases may be exercised by testing. One example environment where these type problems may exist is associated with device drivers. Device drivers are considered important components of software that allow a computer to take advantage of new hardware devices. In order to expand operating system capabilities, these systems should also provide support for new hardware devices, and provide associated device drivers.
Due to the nature of the operating system industry, a large number of device drivers are not written by the operating system manufacturer, but by outside third parties, who are typically hardware owners. Outside third parties typically do not have access to base team development resources available within the manufacturer, and are usually more concerned with quickly getting their device driver to market, otherwise they can not sell their device, and thus receive revenue. This problem is exacerbated by the fact that many of these drivers run in an unprotected kernel mode of the operating system (e.g., ring 0), which often implies that the slightest coding error may cause a system crash, or worse, a corruption to files and/or data.
In another related aspect to the problems described above, many large software systems operate in a highly threaded model, and support “plug in” software models to extend the function of the system. Due to the highly threaded nature of the operating system, plug in device drivers generally must also be highly threaded and programming highly threaded software modules is often complex and time consuming. In the case of device drivers, they generally execute in unprotected kernel mode and any errors can cause a system crash, or corruption.
In many cases, simpler modules that control lower throughput devices may be better served by a less threaded model. The insertion of a less threaded module inside of the highly threaded operating system should not compromise overall system parallelism, but only the throughput of the target device. Due to the current close coupling of the operating systems threading model with the device driver, drivers are generally written in a highly threaded manner, even for lower end hardware devices in order that they do not compromise overall system scale-ability. This can occur when threads “back up” in trying to submit parallel commands to the driver that may employ a single synchronization lock, wherein the concurrency of the I/O model can allow multiple commands to be issued to the driver regardless of how highly threaded it actually is.